package cn.seaboot.admin.upload;

import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * 文件存储
 * <p>
 * 提供最核心的 IO 操作，方便后续程序进行功能扩展。
 * <p>
 * 一般来说，这个接口，可以兼容大部分的 FTP、SMB、云存储。
 * <p>
 * 这属于开发约定，所有的文件上传，统一封装标准。
 * <p>
 * 在这一层代码之上，应当还有一层业务代码，比如说：MultipartFile、File 和 InputStream 应当重载出 3 个函数。
 *
 * @author Mr.css
 * @version 2023-08-24 15:27
 */
public interface Storage {

    /**
     * 存储一份文件
     *
     * @param is   文件输入流
     * @param path 预计存储位置，实际存储在哪儿，取决于存储
     * @return 能够唯一定位到文件的 id（可以是文件路径）
     * @throws IOException 数据写入失败
     */
    String write(InputStream is, String path) throws IOException;

    /**
     * 删除文件
     *
     * @param path 能够唯一定位到文件的 id，也就是 {@link #write(InputStream, String)} 的返回值
     * @throws IOException 文件删除失败
     */
    void delete(String path) throws IOException;

    /**
     * 覆盖一份文件，文件不存在则新建，存在则覆盖文件
     *
     * @param is   文件输入流
     * @param path 能够唯一定位到文件的 id，也就是 {@link #write(InputStream, String)} 的返回值
     * @throws IOException 数据写入失败
     */
    void overwrite(InputStream is, String path) throws IOException;

    /**
     * 将文件复制到输出流中
     * <p>
     * 要获取文件内容，这个函数是最优选项，因为任何场景下，都是可用的，
     * <p>
     * 缺点就是针对特殊场景，还需要额外组织代码。
     *
     * @param path 能够唯一定位到文件的 id，也就是 {@link #write(InputStream, String)} 的返回值
     * @param os   文件输出流
     * @throws IOException 获取文件输入流失败
     */
    void copy(String path, OutputStream os) throws IOException;

    /**
     * 获取文件实体
     * <p>
     * 在做文件分析的时候，可能需要获取完整的文件
     * <p>
     * 这个函数并非任何情况下都有效，只有本机文件和共享文件夹能够做到；
     * 对于 FTP、云存储，可能需要先下载到本地，再构造临时文件。
     * <p>
     * {@link File#createTempFile(String, String)}
     *
     * @param path 相对路径
     * @return InputStream 输入流
     * @throws IOException 获取文件输入流失败
     */
    @NotNull
    File getFile(String path) throws IOException;

    /**
     * 获取文件输入流
     * <p>
     * 这个函数并非任何情况下都有效，ftp 服务是不允许这么封装的。
     *
     * @param path 相对路径
     * @return InputStream 输入流
     * @throws IOException 获取文件输入流失败
     */
    @NotNull
    InputStream openInputStream(String path) throws IOException;
}
